<?php

namespace app\api\controller;

use think\Controller;
use think\Db;

class Wechat extends Controller
{
    // 定义配置项
    private $config = array(
        'APPID'      => 'wx252bed0a4343fec7', // 微信支付APPID.
        'MCHID'      => '1617003785', // 微信支付MCHID 商户收款账号
        'KEY'        => 'sf8522OqTeoBEOvlGW3bin54VBi0UXjN', // 微信支付KEY
        'APPSECRET'  => '', // 公众帐号secert (公众号支付专用)
        'NOTIFY_URL' => 'http://phone.xuanwumobile.com/api/Wechat/huidiao', // 接收支付状态的连接
    );
    public $body;//描述
    public $total_fee;//金额
    public $out_trade_no;//订单号

    // 构造函数
    public function __construct($config = null)
    {
        // 如果配置项为空 则直接返回
        if (!empty($config)) {
            $this->config = $config;
        }
    }


    /**
     * @cc统一下单
     * @param $order 订单 必须包含支付所需要的参数 body(产品描述)、total_fee(订单金额)、out_trade_no(订单号)、product_id(产品id)、trade_type(类型：JSAPI，NATIVE，APP)
     * @param string $notify_url //回调地址
     * @return mixed
     */
    public function WeChatPayReady($order, $notify_url = null)
    {
        // 获取配置项
        $weixinpay_config = $this->config;
        //支付基本参数
        $config = array(
            'appid'            => $weixinpay_config['APPID'],
            'mch_id'           => $weixinpay_config['MCHID'],
            'nonce_str'        => 'test',
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
            'notify_url'       => $weixinpay_config['NOTIFY_URL']
        );
        //设置自定义回调地址
        if ($notify_url) {
            $config['notify_url'] = $notify_url;
        }
        // 合并配置数据和订单数据
        $options = array_merge($order, $config);

        // 生成签名
        $options['sign'] = $this->makeSign($options);
        //参数转xml
        $xml = $this->toXml($options);

        //统一下单API
        $url      = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $header[] = "Content-type: text/xml";//定义content-type为xml,注意是数组
        $ch       = curl_init($url);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);//严格校验
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        $response = curl_exec($ch);
        if (curl_errno($ch)) {
            print curl_error($ch);
        }
        curl_close($ch);
        //返回信息转数组
        $result = $this->toArray($response);

        //失败
        if ($result['return_code'] == 'FAIL' || $result['result_code'] == 'FAIL') {
            return ['status'=>100,'msg'=>$result['return_msg']];
        }

        //签名
        $result['sign']      = $options['sign'];
        $result['nonce_str'] = 'test';
        //返回二次验签后的信息
        return $this->getOrder($result['prepay_id']);
    }

    public function userTiXian($refundNo,$openid,$money,$name){
        $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
        $config_data = [
            'mch_appid' => $this->config['APPID'],
            'mchid' => $this->config['MCHID'],
            'nonce_str' => $this->getRandChar(32),
            'partner_trade_no' => $refundNo,
            'openid' => $openid,
            'check_name' => "FORCE_CHECK",
            're_user_name' => $name,
            'amount' =>  $money*100,
            'desc' => '支分宝转账',
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
        ];
        $sign = $this->makeSign($config_data);
        $config_data['sign'] = $sign;
        $xml = $this->toXml($config_data);
        $response = $this->httpRequest($url,$xml);
        $result = $this->toArray($response);
        if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
            return ['status'=>200,'msg'=>$result['payment_no']];
        }else if($result['return_code'] == 'FAIL'){
            return ['status'=>100,'msg'=>$result['return_msg']];
        }else{
            if($result['err_code'] == 'SENDNUM_LIMIT'){
                return ['status'=>100,'msg'=>'单个用户每天最多可提现3次'];
            }
            return ['status'=>100,'msg'=>$result['err_code_des']];
        }
    }
    /**
     * 获取时间
     * @return array
     */
    public function getDateBytimeDate($string)
    {
        $replacement  = '-';
        $replacement2 = ':';
        $a            = substr_replace($string, $replacement, 4, 0);
        $b            = substr_replace($a, $replacement, 7, 0);
        $c            = substr_replace($b, ' ', 10, 0);
        $d            = substr_replace($c, $replacement2, 13, 0);
        $e            = substr_replace($d, $replacement2, 16, 0);
        return $e;
    }

    /*
    * 发送请求
    * @param  string $url      请求的url地址
    * @param  array  $postData 请求的数据
    */
    public function httpRequest($url, $postData = [])
    {
        $header[] = "Content-type: text/xml";//定义content-type为xml,注意是数组
        // 初始化curl
        $ch = curl_init();
        // 设置请求的url地址
        curl_setopt($ch, CURLOPT_URL, $url);
        // 将curl_exec()获取的信息以字符串返回，而不是直接输出。
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // 发送post请求
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        //curl注意事项，如果发送的请求是https，必须要禁止服务器端校检SSL证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
        curl_setopt($ch,CURLOPT_SSLCERT,ROOT_PATH.'/public/apiclient_cert.pem');
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
        curl_setopt($ch,CURLOPT_SSLKEY,ROOT_PATH.'/public/apiclient_key.pem');
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

        // 执行curl
        $result = curl_exec($ch);
        if (curl_errno($ch)) {
            print curl_error($ch);
        }
        // 关闭curl
        curl_close($ch);

        return $result;
    }

    /**
     * 生成签名
     * @return 签名，本函数不覆盖sign成员变量，如要设置签名需要调用SetSign方法赋值
     */
    public function makeSign($data)
    {
        // 去空
        $data = array_filter($data);
        //签名步骤一：按字典序排序参数
        ksort($data);
        $string_a = http_build_query($data);
        $string_a = urldecode($string_a);
        //签名步骤二：在string后加入KEY
        $config           = $this->config;
        $string_sign_temp = $string_a . "&key=" . $config['KEY'];
        //签名步骤三：MD5加密
        $sign = md5($string_sign_temp);
        // 签名步骤四：所有字符转为大写
        $result = strtoupper($sign);
        return $result;
    }

    /**
     * 将xml转为array
     * @param string $xml xml字符串
     * @return array       转换得到的数组
     */
    public function toArray($xml)
    {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $result = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $result;
    }

    /**
     * 输出xml字符
     * @throws WxPayException
     **/
    public function toXml($data)
    {
        //var_dump($data);
        if (!is_array($data) || count($data) <= 0) {
            //throw new WxPayException("数组数据异常！");
        }
        $xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    //获取指定长度的随机字符串
    function getRandChar($length)
    {
        $str    = null;
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max    = strlen($strPol) - 1;

        for ($i = 0; $i < $length; $i++) {
            $str .= $strPol[rand(0, $max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
        }

        return $str;
    }

    //执行第二次签名，才能返回给客户端使用
    public function getOrder($prepayId)
    {
        $data["appid"]     = $this->config["APPID"];
        $data["noncestr"]  = $this->getRandChar(32);
        $data["package"]   = $prepayId;
        $data["partnerid"] = $this->config['MCHID'];
//        $data["prepayid"] = $prepayId;
        $data["timestamp"] = (string)time();
//        $s = $this->makeSign($data, false);
        $s            = md5('appId=' . $this->config['APPID'] . '&nonceStr=' . $data["noncestr"] . '&package=prepay_id=' . $data["package"] . '&signType=MD5&timeStamp=' . $data["timestamp"] . '&key=' . $this->config['KEY']);
        $data["sign"] = $s;

        return $data;
    }
    /**
     * 验证
     * @return array 返回数组格式的notify数据
     */
    public function huidiao(){
        // 获取xml
        $xml=file_get_contents('php://input', 'r');
        // 转成php数组
        $getInfo=$this->toArray($xml);
//        $this->write_admin_log($getInfo);
        // 保存原sign
        $data_sign=$getInfo['sign'];
        // sign不参与签名
        unset($getInfo['sign']);
        $sign=$this->makeSign($getInfo);
        // 判断签名是否正确  判断支付状态
        if ($sign===$data_sign && $getInfo['return_code']=='SUCCESS' && $getInfo['result_code']=='SUCCESS') {
            $back_order_id = $getInfo['transaction_id']; // 订单号
            $order_number = $getInfo['out_trade_no'];;
            $order = Db::table('up_order')
                ->where('order_number', $order_number)
                ->field('order_id, order_jc_total_days, order_jc_sy_days, order_jc_datetime, 
            order_jc_date, order_is_pay, order_jc_now_price')
                ->find();
            $oi = Db::table('up_order_info')
                ->where('oi_order_id', $order['order_id'])
                ->where('oi_type', 2)
                ->field('oi_days, oi_price, oi_zhejiu_price, oi_id, oi_pay')
                ->order('oi_time desc')
                ->find();

            $dq_time = date('Y-m-d H:i:s', strtotime("+{$oi['oi_days']}days", strtotime($order['order_jc_datetime'])));
            $dq_date = date('Y-m-d', strtotime("+{$oi['oi_days']}days", strtotime($order['order_jc_date'])));

            if($order['order_is_pay'] == 1){
                Db::table('up_order')->where('order_id', $order['order_id'])
                    ->update([
                        'order_is_pay' => 2,
                        'order_pay_time' => $this->create_time,
                        'order_jc_now_price' => $order['order_jc_now_price'] - $oi['oi_zhejiu_price'],
                        'order_jc_total_days' => $order['order_jc_total_days'] + $oi['oi_days'],
                        'order_jc_price' => $oi['oi_price'],
                        'order_jc_days' => $oi['oi_days'],
                        'order_jc_sy_days' => $order['order_jc_sy_days'] + $oi['oi_days'],
                        'order_jc_datetime' => $dq_time,
                        'order_jc_date' => $dq_date
                    ]);

                Db::table('up_order_info')->where('oi_id', $oi['oi_id'])
                    ->update([
                        'oi_pay' => 2
                    ]);
            }
            $result = true;
        } else{
            $result = false;
        }
        // 返回状态给微信服务器----------------
        if ($result) {
            $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        }else{
            $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
        }
        echo $str;
        exit();
    }
    /**
     * 验证
     * @return array 返回数组格式的notify数据
     */
    public function huidiao1(){
        // 获取xml
        $xml=file_get_contents('php://input', 'r');
        // 转成php数组
        $getInfo=$this->toArray($xml);
//        $this->write_admin_log($getInfo);
        // 保存原sign
        $data_sign=$getInfo['sign'];
        // sign不参与签名
        unset($getInfo['sign']);
        $sign=$this->makeSign($getInfo);
        // 判断签名是否正确  判断支付状态
        if ($sign===$data_sign && $getInfo['return_code']=='SUCCESS' && $getInfo['result_code']=='SUCCESS') {
            $back_order_id = $getInfo['transaction_id']; // 订单号
            $order_number = $getInfo['out_trade_no'];;
            $order = Db::table('up_order')
                ->where('order_number', $order_number)
                ->field('order_id, order_is_pay')
                ->find();

            $oi = Db::table('up_order_info')
                ->where('oi_order_id', $order['order_id'])
                ->where('oi_type', 2)
                ->field('oi_days, oi_price, oi_zhejiu_price, oi_id, oi_pay')
                ->order('oi_time desc')
                ->find();

            if($order['order_is_pay'] == 1){
                Db::table('up_order')->where('order_id', $order['order_id'])
                    ->update([
                        'order_is_pay' => 2,
                        'order_status' => 7,
                        'order_pay_time' => $this->create_time
                    ]);

                Db::table('up_order_info')->where('oi_id', $oi['oi_id'])
                    ->update([
                        'oi_pay' => 2
                    ]);
            }
            $result = true;
        } else{
            $result = false;
        }
        // 返回状态给微信服务器----------------
        if ($result) {
            $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        }else{
            $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
        }
        echo $str;
        exit();
    }

}